package service

import (
	"cooke-home/auth-service/mapper"
	"cooke-home/auth-service/model/dto"
	"cooke-home/auth-service/model/vo"
	"errors"
	"fmt"
	"time"

	"github.com/golang-jwt/jwt/v5"
)

var jwtSecret = []byte("3391C4AB0C594382985EDE2C7BCAD51F")

type UserServiceImpl struct {
	um mapper.UserMapper
}

func NewUserServiceImpl(userMapper mapper.UserMapper) *UserServiceImpl {
	return &UserServiceImpl{
		um: userMapper,
	}
}

func (usi *UserServiceImpl) Login(loginDto dto.LoginDto) (*vo.LoginResponseVo, error) {
	user, err := usi.um.GetUserByUsernameAndPassword(loginDto.Username, loginDto.Password)
	if err != nil {
		return nil, errors.New("用户名或密码错误")
	}

	// Access token (short-lived)
	accessExpire := time.Now().Add(15 * time.Minute) // 15 minutes
	accessClaims := jwt.RegisteredClaims{
		Subject:   fmt.Sprintf("%d", user.UserId), // 用户主键
		ExpiresAt: jwt.NewNumericDate(accessExpire),
		IssuedAt:  jwt.NewNumericDate(time.Now()),
	}
	accessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, accessClaims)
	accessString, _ := accessToken.SignedString(jwtSecret)

	// Refresh token (long-lived)
	refreshExpire := time.Now().Add(7 * 24 * time.Hour) // 7 days
	refreshClaims := jwt.RegisteredClaims{
		Subject:   fmt.Sprintf("%d", user.UserId),
		ExpiresAt: jwt.NewNumericDate(refreshExpire),
		IssuedAt:  jwt.NewNumericDate(time.Now()),
	}
	refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, refreshClaims)
	refreshString, _ := refreshToken.SignedString(jwtSecret)

	return &vo.LoginResponseVo{
		Token:        accessString,
		RefreshToken: refreshString,
		Expire:       int64(time.Until(accessExpire).Seconds()),
	}, nil
}

func (usi *UserServiceImpl) RefreshAccessToken(refreshTokenDto dto.RefreshTokenDto) (*vo.LoginResponseVo, error) {
	token, err := jwt.ParseWithClaims(refreshTokenDto.RefreshToken, &jwt.RegisteredClaims{}, func(token *jwt.Token) (interface{}, error) {
		return jwtSecret, nil
	})

	if err != nil {
		return nil, errors.New("无效的刷新令牌")
	}

	claims, ok := token.Claims.(*jwt.RegisteredClaims)
	if !ok || !token.Valid {
		return nil, errors.New("无效的刷新令牌")
	}

	// Check if refresh token is expired
	if claims.ExpiresAt.Before(time.Now()) {
		return nil, errors.New("刷新令牌已过期")
	}

	// Generate new access token
	accessExpire := time.Now().Add(15 * time.Minute)
	accessClaims := jwt.RegisteredClaims{
		Subject:   claims.Subject,
		ExpiresAt: jwt.NewNumericDate(accessExpire),
		IssuedAt:  jwt.NewNumericDate(time.Now()),
	}
	accessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, accessClaims)
	accessString, _ := accessToken.SignedString(jwtSecret)

	// Generate new refresh token (optional - extend refresh token life)
	refreshExpire := time.Now().Add(7 * 24 * time.Hour)
	refreshClaims := jwt.RegisteredClaims{
		Subject:   claims.Subject,
		ExpiresAt: jwt.NewNumericDate(refreshExpire),
		IssuedAt:  jwt.NewNumericDate(time.Now()),
	}
	newRefreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, refreshClaims)
	refreshString, _ := newRefreshToken.SignedString(jwtSecret)

	return &vo.LoginResponseVo{
		Token:        accessString,
		RefreshToken: refreshString,
		Expire:       int64(time.Until(accessExpire).Seconds()),
	}, nil
}
